/**
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.jimm.protocols.icq;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
 * <p>
 * Created by
 * 
 * @author Fabrice Michellonet
 * @author Konovalov Aleksey
 * 
 *         Использован код Jimm
 */
public class Snac extends DataContainer {

	/**************************/
	/* Family 0x0001: SERVICE */
	/**************************/

	public static final int SERVICE_FAMILY = 0x0001;

	public static final int CLI_READY_COMMAND = 0x0002;
	public static final int SRV_FAMILIES_COMMAND = 0x0003;
	public static final int CLI_RATESREQUEST_COMMAND = 0x0006;
	public static final int SRV_RATES_COMMAND = 0x0007;
	public static final int CLI_ACKRATES_COMMAND = 0x0008;
	public static final int CLI_REQINFO_COMMAND = 0x000E;
	public static final int SRV_REPLYINFO_COMMAND = 0x000F;
	public static final int SRV_MOTD_COMMAND = 0x0013;
	public static final int CLI_FAMILIES_COMMAND = 0x0017;
	public static final int SRV_FAMILIES2_COMMAND = 0x0018;
	public static final int CLI_SETSTATUS_COMMAND = 0x001E;

	/***************************/
	/* Family 0x0002: LOCATION */
	/***************************/

	public static final int LOCATION_FAMILY = 0x0002;

	public static final int CLI_REQLOCATION_COMMAND = 0x0002;
	public static final int SRV_REPLYLOCATION_COMMAND = 0x0003;
	public static final int CLI_SETUSERINFO_COMMAND = 0x0004;

	/**************************/
	/* Family 0x0003: CONTACT */
	/**************************/

	public static final int CONTACT_FAMILY = 0x0003;

	public static final int CLI_REQBUDDY_COMMAND = 0x0002;
	public static final int SRV_REPLYBUDDY_COMMAND = 0x0003;
	public static final int CLI_BUDDYLIST_ADD_COMMAND = 0x0004;
	public static final int CLI_BUDDYLIST_REMOVE_COMMAND = 0x0005;
	public static final int SRV_USERONLINE_COMMAND = 0x000B;
	public static final int SRV_USEROFFLINE_COMMAND = 0x000C;

	/***********************/
	/* Family 0x0004: ICBM */
	/***********************/

	public static final int CLI_ICBM_FAMILY = 0x0004;

	public static final int CLI_SETICBM_COMMAND = 0x0002;
	public static final int CLI_REQICBM_COMMAND = 0x0004;
	public static final int SRV_REPLYICBM_COMMAND = 0x0005;
	public static final int CLI_SENDMSG_COMMAND = 0x0006;
	public static final int SRV_RECVMSG_COMMAND = 0x0007;
	public static final int SRV_MISSED_MESSAGE_COMMAND = 0x000A;
	public static final int CLI_ACKMSG_COMMAND = 0x000B;
	public static final int CLI_MTN_COMMAND = 0x0014;
	public static final int SRV_MTN_COMMAND = 0x0014;

	/**********************/
	/* Family 0x0009: BOS */
	/**********************/

	public static final int BOS_FAMILY = 0x0009;

	public static final int CLI_REQBOS_COMMAND = 0x0002;
	public static final int SRV_REPLYBOS_COMMAND = 0x0003;

	/***************************/
	/* Family 0x000B: INTERVAL */
	/***************************/

	// Nothing

	/*************************/
	/* Family 0x0013: ROSTER */
	/*************************/

	public static final int SSI_FAMILY = 0x0013;

	public static final int CLI_REQLISTS_COMMAND = 0x0002;
	public static final int SRV_REPLYLISTS_COMMAND = 0x0003;
	public static final int CLI_REQROSTER_COMMAND = 0x0004;
	public static final int CLI_CHECKROSTER_COMMAND = 0x0005;
	public static final int SRV_REPLYROSTER_COMMAND = 0x0006;
	public static final int CLI_ROSTERACK_COMMAND = 0x0007;
	public static final int CLI_ROSTERADD_COMMAND = 0x0008;
	public static final int CLI_ROSTERUPDATE_COMMAND = 0x0009;
	public static final int CLI_ROSTERDELETE_COMMAND = 0x000A;
	public static final int SRV_UPDATEACK_COMMAND = 0x000E;
	public static final int SRV_REPLYROSTEROK_COMMAND = 0x000F;
	public static final int CLI_ADDSTART_COMMAND = 0x0011;
	public static final int CLI_ADDEND_COMMAND = 0x0012;
	public static final int CLI_GRANT_FUTURE_AUTH_COMMAND = 0x0014;
	public static final int SRV_GRANT_FUTURE_AUTH_COMMAND = 0x0015;
	public static final int CLI_REMOVEME_COMMAND = 0x0016;
	public static final int CLI_REQAUTH_COMMAND = 0x0018;
	public static final int SRV_AUTHREQ_COMMAND = 0x0019;
	public static final int CLI_AUTHORIZE_COMMAND = 0x001A;
	public static final int SRV_AUTHREPLY_COMMAND = 0x001B;
	public static final int SRV_ADDEDYOU_COMMAND = 0x001C;

	/**************************/
	/* Family 0x0015: OLD ICQ */
	/**************************/

	public static final int OLD_ICQ_FAMILY = 0x0015;

	public static final int SRV_TOICQERR_COMMAND = 0x0001;
	public static final int CLI_TOICQSRV_COMMAND = 0x0002;
	public static final int SRV_FROMICQSRV_COMMAND = 0x0003;

	private static final int SNAC_HEADER_SIZE = 10;

	ByteArrayOutputStream header = new ByteArrayOutputStream(SNAC_HEADER_SIZE);
	private int familyId;
	private int subTypeId;
	private byte flag0;
	private byte flag1;
	private int requestId;

	private Snac() {
		headerModified = true;
	}

	/**
	 * Create a Snac.
	 * 
	 * @param familyID
	 *            Snac's family ID.
	 * @param subTypeID
	 *            Snac's sub Type ID.
	 * @param flag0
	 *            Snac's flag0.
	 * @param flag1
	 *            Snac's flag1.
	 * @param requestID
	 *            Snac's request ID.
	 */
	public Snac(int familyID, int subTypeID, int flag0, int flag1,
			int requestID) {
		this();
		familyId = familyID;
		subTypeId = subTypeID;
		this.flag0 = (byte)flag0;
		this.flag1 = (byte)flag1;
		requestId = requestID;
	}

	public Snac(DataInputStream strm, int size) throws IOException {
		this();

		familyId = strm.readUnsignedShort();
		subTypeId = strm.readUnsignedShort();
		flag0 = strm.readByte();
		flag1 = strm.readByte();
		requestId = strm.readInt();

		// FIXME тут тоже не надо делать таких махинаций
		byte[] dataFieldArray = new byte[size - 10];
		strm.read(dataFieldArray);

		this.addRawDataToSnac(new RawData(dataFieldArray));
	}

	/**
	 * 
	 * @return The Snac's Family ID.
	 */
	public int getFamilyId() {
		return familyId;
	}

	/**
	 * 
	 * @return The Snac's Sub Type ID.
	 */
	public int getSubTypeId() {
		return subTypeId;
	}

	/**
	 * 
	 * @return The Snac's fisrt flag.
	 */
	public byte getFlag0() {
		return flag0;
	}

	/**
	 * 
	 * @return The Snac's second flag.
	 */
	public byte getFlag1() {
		return flag1;
	}

	/**
	 * 
	 * @return The Snac's Request ID.
	 */
	public int getRequestId() {
		return requestId;
	}

	/**
	 * This define the request Id of the Snac.
	 * 
	 * @param requestId
	 *            The request Id of the Snac.
	 */
	public void setRequestId(int requestId) {
		this.requestId = requestId;
		headerModified = true;
	}

	/**
	 * This function allow to add a TLV into the Snac.
	 * 
	 * @param tlv
	 *            The TLV to be added.
	 * @throws IOException 
	 */
	public void addTlvToSnac(Tlv tlv) {
		addDataField(tlv);
	}

	/**
	 * This function add a Raw Data into the Snac.
	 * 
	 * @param rawData
	 *            The Raw Data to be added.
	 * @throws IOException 
	 */
	public void addRawDataToSnac(RawData rawData) {
		addDataField(rawData);
	}

	public byte[] getHeaderByteArray() {
		if (headerModified) {
			header.reset();
			DataOutputStream strm = new DataOutputStream(header);

			/* Adding Header fields */
			try {
				strm.writeShort(familyId);
				strm.writeShort(subTypeId);
				strm.writeByte(flag0);
				strm.writeByte(flag1);
				strm.writeInt(requestId);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return header.toByteArray();
	}
}